package jannex.sql;

import jannex.Builder;
import jannex.Consumer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Fetcher<E> implements Iterable<E> {

    private final Builder<TypedResultSet<E>> builder;

    public Fetcher(Builder<TypedResultSet<E>> builder) {
        this.builder = builder;
    }

    public List<E> toList() {
        List<E> list = new ArrayList<>();
        try (TypedResultSet<E> resultSet = builder.build()) {
            while (resultSet.next()) {
                list.add(resultSet.getObject());
            }
        }
        return list;
    }

    public Set<E> toSet() {
        Set<E> set = new HashSet<>();
        try (TypedResultSet<E> resultSet = builder.build()) {
            while (resultSet.next()) {
                set.add(resultSet.getObject());
            }
        }
        return set;
    }

    @SuppressWarnings("unchecked")
    public <K> Map<K, E> toMap(String keyLabel) {
        Map<K, E> map = new HashMap<>();
        try (TypedResultSet<E> resultSet = builder.build()) {
            while (resultSet.next()) {
                K key = (K) resultSet.getObject(keyLabel);
                E value = resultSet.getObject();
                map.put(key, value);
            }
        }
        return map;
    }

    public <K> Map<K, E> toMap(String keyLabel, Class<K> keyType) {
        Map<K, E> map = new HashMap<>();
        try (TypedResultSet<E> resultSet = builder.build()) {
            while (resultSet.next()) {
                K key = resultSet.getObject(keyLabel, keyType);
                E value = resultSet.getObject();
                map.put(key, value);
            }
        }
        return map;
    }

    public void iterate(Consumer<E> consumer) {
        try (TypedResultSet<E> resultSet = builder.build()) {
            while (resultSet.next()) {
                consumer.accept(resultSet.getObject());
            }
        }
    }

    public E first() {
        try (TypedResultSet<E> resultSet = builder.build()) {
            if (!resultSet.next()) {
                return null;
            }
            return resultSet.getObject();
        }
    }

    @Override
    public Iterator<E> iterator() {
        return toList().iterator();
    }

}
